package dalgo.reglas;

import java.util.LinkedList;

import javax.rmi.CORBA.Util;

import uniandes.cupi2.collections.arbol.arbolBinario.ArbolBinario;
import uniandes.cupi2.collections.arbol.arbolBinario.NodoArbolBinario;
import dalgo.main.Estado;
import dalgo.main.Main;
import dalgo.utils.Utils;

public class Aislamiento extends Regla {

	@Override
	public LinkedList<Estado> aplicarRegla(ArbolBinario<String> arbol,
			int idPadre) {
		LinkedList<Estado> ret = new LinkedList<Estado>();
		NodoArbolBinario<String> hijoDer = arbol.darRaiz().darDerecho();
		NodoArbolBinario<String> hijoIzq = arbol.darRaiz().darIzquierdo();

		 
			String temp = hijoDer.buscar(Main.getVariable());

			if (temp != null) {

				String elemento = hijoDer.darElemento();
				ret.add(operador(elemento, arbol.darRaiz(), idPadre));
			} else {
				String elemento = hijoIzq.darElemento();
				Estado e = operador(elemento, arbol.darRaiz(), idPadre);

				ret.add(e);
			}
		
		return ret;
	}

	
	/**
	 * Elimina un log elevando ambos lados con 2^ pre: Entra como raiz el =
	 */
	private Estado log(NodoArbolBinario<String> raiz, int idPadre) {

		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();
		if (hIzq.darElemento().equals(LOG)) {
			NodoArbolBinario<String> hijo = hIzq.darDerecho();
			raiz.encadenarIzquierdo(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(
					INVLOG);
			nuevo.encadenarDerecho(hIzq);
			raiz.encadenarIzquierdo(nuevo);
		}

		if (hDer.darElemento().equals(LOG)) {
			NodoArbolBinario<String> hijo = hDer.darDerecho();
			raiz.encadenarDerecho(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(
					INVLOG);
			nuevo.encadenarDerecho(hDer);
			raiz.encadenarDerecho(nuevo);
		}

		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre,"Aislamiento- Logaritmo");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo 2^ aplicando log pre: Entra como raiz el =
	 */
	private Estado logInv(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();
		if (hIzq.darElemento().equals(INVLOG)) {
			NodoArbolBinario<String> hijo = hIzq.darDerecho();
			raiz.encadenarIzquierdo(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(LOG);
			nuevo.encadenarDerecho(hIzq);
			raiz.encadenarIzquierdo(nuevo);
		}

		if (hDer.darElemento().equals(INVLOG)) {
			NodoArbolBinario<String> hijo = hDer.darDerecho();
			raiz.encadenarDerecho(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(LOG);
			nuevo.encadenarDerecho(hDer);
			raiz.encadenarDerecho(nuevo);
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre, "Aislamiento- 2^");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo rz aplicando ^2 pre: entra como raiz el =
	 */
	private Estado raiz(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();
		if (hIzq.darElemento().equals(RAIZ)) {
			NodoArbolBinario<String> hijo = hIzq.darDerecho();
			raiz.encadenarIzquierdo(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(
					CUADRADO);
			nuevo.encadenarDerecho(hIzq);
			raiz.encadenarIzquierdo(nuevo);
		}

		if (hDer.darElemento().equals(RAIZ)) {
			NodoArbolBinario<String> hijo = hDer.darDerecho();
			raiz.encadenarDerecho(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(
					CUADRADO);
			nuevo.encadenarDerecho(hDer);
			raiz.encadenarDerecho(nuevo);
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre,"Aislamiento- Raiz Cuadrada");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo ^2 aplicando rz pre: Entra como raiz el =
	 */
	private Estado cuadrado(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();
		if (hIzq.darElemento().equals(CUADRADO)) {
			NodoArbolBinario<String> hijo = hIzq.darDerecho();
			raiz.encadenarIzquierdo(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(RAIZ);
			nuevo.encadenarDerecho(hIzq);
			raiz.encadenarIzquierdo(nuevo);
		}

		if (hDer.darElemento().equals(CUADRADO)) {
			NodoArbolBinario<String> hijo = hDer.darDerecho();
			raiz.encadenarDerecho(hijo);
		} else {
			NodoArbolBinario<String> nuevo = new NodoArbolBinario<String>(RAIZ);
			nuevo.encadenarDerecho(hDer);
			raiz.encadenarDerecho(nuevo);
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre, "Aislamiento- ^2");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo x + a = b pre: entra como raiz el =
	 */
	private Estado suma(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();

		if (hIzq.darElemento().equals(SUMA)) {
			NodoArbolBinario<String> val1 = hIzq.darIzquierdo();
			NodoArbolBinario<String> val2 = hIzq.darDerecho();
			String reDer = val1.buscar(Main.getVariable());
			if (reDer != null) {
				raiz.encadenarIzquierdo(val1);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						RESTA);
				raiz.encadenarDerecho(menos);
				menos.encadenarDerecho(val2);
				menos.encadenarIzquierdo(hDer);
			} else {
				raiz.encadenarIzquierdo(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						RESTA);
				raiz.encadenarDerecho(menos);
				menos.encadenarDerecho(val1);
				menos.encadenarIzquierdo(hDer);
			}
		} else {
			NodoArbolBinario<String> val1 = hDer.darIzquierdo();
			NodoArbolBinario<String> val2 = hDer.darDerecho();
			String reDer = val1.buscar(Main.getVariable());
			if (reDer != null) {
				raiz.encadenarDerecho(val1);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						RESTA);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val2);
			} else {
				raiz.encadenarDerecho(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						RESTA);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val1);
			}
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre,"Aislamiento- Suma");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo x + a = b pre: entra como raiz el =
	 */
	private Estado resta(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();

		if (hIzq.darElemento().equals(RESTA)) {
			NodoArbolBinario<String> val1 = hIzq.darIzquierdo();
			NodoArbolBinario<String> val2 = hIzq.darDerecho();
			String reDer = val1.buscar(Main.getVariable());
			if (reDer != null) {
				raiz.encadenarIzquierdo(val1);
				NodoArbolBinario<String> mas = new NodoArbolBinario<String>(
						SUMA);
				raiz.encadenarDerecho(mas);
				mas.encadenarDerecho(val2);
				mas.encadenarIzquierdo(hDer);

			} else {
				raiz.encadenarIzquierdo(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						SUMA);
				raiz.encadenarDerecho(menos);
				menos.encadenarDerecho(val1);
				menos.encadenarIzquierdo(hDer);
			}
		} else {
			NodoArbolBinario<String> val1 = hDer.darIzquierdo();
			NodoArbolBinario<String> val2 = hDer.darDerecho();
			String reDer = val1.buscar(Main.getVariable());
			if (reDer != null) {
				raiz.encadenarDerecho(val1);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						SUMA);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val2);
			} else {
				raiz.encadenarDerecho(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						SUMA);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val1);
			}
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre, "Aislamiento- Resta");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo x * a = b pre: entra como raiz el =
	 */
	private Estado multiplicacion(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();

		if (hIzq.darElemento().equals(MULTIPLICACION)) {
			NodoArbolBinario<String> val1 = hIzq.darIzquierdo();
			NodoArbolBinario<String> val2 = hIzq.darDerecho();
			if (val1.darElemento().equals(Main.getVariable())) {
				raiz.encadenarIzquierdo(val1);
				NodoArbolBinario<String> mas = new NodoArbolBinario<String>(
						DIVISION);
				raiz.encadenarDerecho(mas);
				mas.encadenarDerecho(val2);
				mas.encadenarIzquierdo(hDer);

			} else {
				raiz.encadenarIzquierdo(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						DIVISION);
				raiz.encadenarDerecho(menos);
				menos.encadenarDerecho(val1);
				menos.encadenarIzquierdo(hDer);
			}
		} else {
			NodoArbolBinario<String> val1 = hDer.darIzquierdo();
			NodoArbolBinario<String> val2 = hDer.darDerecho();
			if (val1.darElemento().equals(Main.getVariable())) {
				raiz.encadenarDerecho(val1);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						DIVISION);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val2);
			} else {
				raiz.encadenarDerecho(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						DIVISION);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val1);
			}
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre,"Aislamiento- Multiplicacion");

		return e;
	}

	/**
	 * Transforma ecuaciones del tipo x / a = b pre: entra como raiz el =
	 */
	private Estado division(NodoArbolBinario<String> raiz, int idPadre) {
		NodoArbolBinario<String> hIzq = raiz.darIzquierdo();
		NodoArbolBinario<String> hDer = raiz.darDerecho();

		if (hIzq.darElemento().equals(DIVISION)) {
			NodoArbolBinario<String> val1 = hIzq.darIzquierdo();
			NodoArbolBinario<String> val2 = hIzq.darDerecho();
			if (val1.darElemento().equals(Main.getVariable())) {
				raiz.encadenarIzquierdo(val1);
				NodoArbolBinario<String> mas = new NodoArbolBinario<String>(
						MULTIPLICACION);
				raiz.encadenarDerecho(mas);
				mas.encadenarDerecho(val2);
				mas.encadenarIzquierdo(hDer);

			} else {
				raiz.encadenarIzquierdo(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						MULTIPLICACION);
				raiz.encadenarDerecho(menos);
				menos.encadenarDerecho(val1);
				menos.encadenarIzquierdo(hDer);
			}
		} else {
			NodoArbolBinario<String> val1 = hDer.darIzquierdo();
			NodoArbolBinario<String> val2 = hDer.darDerecho();
			if (val1.darElemento().equals(Main.getVariable())) {
				raiz.encadenarDerecho(val1);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						MULTIPLICACION);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val2);
			} else {
				raiz.encadenarDerecho(val2);
				NodoArbolBinario<String> menos = new NodoArbolBinario<String>(
						MULTIPLICACION);
				raiz.encadenarIzquierdo(menos);
				menos.encadenarIzquierdo(hIzq);
				menos.encadenarDerecho(val1);
			}
		}
		ArbolBinario<String> arbol = new ArbolBinario<String>();

		arbol.definirRaiz(raiz);
		Estado e = new Estado(arbol, idPadre, "Aislamiento- Division");

		return e;
	}

	private Estado operador(String op, NodoArbolBinario<String> raiz,
			int idPadre) {
		if (op.equals(LOG)) {
			return log(raiz, idPadre);
		} else if (op.equals(INVLOG)) {
			return logInv(raiz, idPadre);
		} else if (op.equals(RAIZ)) {
			return raiz(raiz, idPadre);
		} else if (op.equals(CUADRADO)) {
			return cuadrado(raiz, idPadre);
		} else if (op.equals(SUMA)) {
			return suma(raiz, idPadre);
		} else if (op.equals(RESTA)) {
			return resta(raiz, idPadre);
		} else if (op.equals(MULTIPLICACION)) {
			return multiplicacion(raiz, idPadre);
		} else {
			return division(raiz, idPadre);
		}
	}

	

}
